home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / memory / xms200je / xms.cpp < prev    next >
C/C++ Source or Header  |  1993-11-22  |  13KB  |  486 lines

  1. //--------------------------------------------------------------------------
  2. //
  3. //      XMS.CPP: body of XMS interface library.
  4. //      Copyright (c) J.English 1993.
  5. //      Author's address: je@unix.brighton.ac.uk
  6. //
  7. //      Permission is granted to use copy and distribute the
  8. //      information contained in this file provided that this
  9. //      copyright notice is retained intact and that any software
  10. //      or other document incorporating this file or parts thereof
  11. //      makes the source code for the library of which this file
  12. //      is a part freely available.
  13. //
  14. //--------------------------------------------------------------------------
  15. //
  16. //      Revision history:
  17. //      2.0     Nov 1993        Initial coding
  18. //
  19. //--------------------------------------------------------------------------
  20.  
  21. #include "xms.h"
  22. #include <dos.h>
  23. #include <mem.h>
  24. #include <stdlib.h>
  25.  
  26. //--------------------------------------------------------------------------
  27. //
  28. //      Data structure declarations.
  29. //
  30. struct XMSmove              // descriptor for XMS moves
  31. {
  32.     long count;             // ... number of bytes to move
  33.     int  srchandle;         // ... source handle (0 for real memory)
  34.     long srcoffset;         // ... source offset (or far pointer)
  35.     int  dsthandle;         // ... destination handle (0 for real memory)
  36.     long dstoffset;         // ... destination offset (or far pointer)
  37. };
  38.  
  39.  
  40. //--------------------------------------------------------------------------
  41. //
  42. //      Constants.
  43. //
  44. const long K    = 1024;     // size of a kilobyte in bytes
  45. const int  PARA = 16;       // size of a paragraph in bytes
  46.  
  47.  
  48. //--------------------------------------------------------------------------
  49. //
  50. //      Globals (statics).
  51. //
  52. static void far (*XMSdriver)() = 0;     // pointer to XMS driver routine
  53. static int      XMSinited      = 0;     // has XMSinit been called already?
  54. static XMSmove  descriptor;             // why use more than one?
  55. static int      A20enabled;             // original A20 state
  56.  
  57. //--------------------------------------------------------------------------
  58. //
  59. //      XMSinit: initialise XMS system (first time only).
  60. //
  61. //      The first time it is called, this function locates the XMS driver
  62. //      and allocates a handle for a zero-byte block.  It returns TRUE if
  63. //      a handle was successfully allocated.  Subsequent calls return the
  64. //      same value.
  65. //
  66. static XMS::error XMSinit ()
  67. {
  68.     //--- check if this is the first time XMSinit has been called
  69.     if (XMSinited == 0)
  70.     {
  71.         //--- now it isn't!
  72.         XMSinited = 1;
  73.  
  74.         //--- check if an XMS driver is present (magic spell)
  75.         REGS r;
  76.         r.x.ax = 0x4300;
  77.         int86 (0x2F, &r, &r);
  78.         if (r.h.al != 0x80)
  79.             return XMS::NO_DRIVER;
  80.  
  81.         //--- get the XMS driver's address (magic spell)
  82.         SREGS s;
  83.         r.x.ax = 0x4310;
  84.         int86x (0x2F, &r, &r, &s);
  85.         XMSdriver = (void far (*)()) MK_FP(s.es,r.x.bx);
  86.     }
  87.  
  88.     //--- return success indicator
  89.     return (XMSdriver != 0 ? XMS::SUCCESS : XMS::NO_DRIVER);
  90. }
  91.  
  92.  
  93. //--------------------------------------------------------------------------
  94. //
  95. //      XMScopy: copy block to/from XMS.
  96. //
  97. //      This function copies data in accordance with the parameters set
  98. //      up in the structure "descriptor".  Overlapping blocks may not be
  99. //      handled correctly (as per XMS specification).  It does nothing if
  100. //      XMS initialisation fails.
  101. //
  102. static XMS::error XMScopy ()
  103. {
  104.     XMS::error result = XMSinit ();
  105.     if (result == XMS::SUCCESS)
  106.     {   _SI = FP_OFF (&descriptor);
  107.         _AH = 0x0B;
  108.         XMSdriver ();
  109.         if (_AX == 0)
  110.             result = XMS::error (_BL);
  111.     }
  112.     return result;
  113. }
  114.  
  115. //--------------------------------------------------------------------------
  116. //
  117. //      XMS::XMS.
  118. //
  119. //      Constructor for class XMS.  Initialises XMSdriver if necessary,
  120. //      and attempts to allocate a block of the specified number of bytes
  121. //      (which will be rounded up to the nearest K).
  122. //
  123. XMS::XMS (long size)
  124. {
  125.     handle = 0;
  126.     allocation = 0;
  127.     if ((status = XMSinit()) == SUCCESS)
  128.     {   int result = 0;
  129.         int realsize;
  130.         size += K - 1;
  131.         int request = size / K;
  132.         _DX = request;
  133.         _AH = 0x09;
  134.         XMSdriver ();
  135.         result = _AX;
  136.         if (result)
  137.         {   handle = _DX;
  138.             _AH = 0x0E;
  139.             XMSdriver ();
  140.             result = _AX;
  141.             realsize = _DX;
  142.         }
  143.         else
  144.             status = error (_BL);
  145.         if (result)
  146.             allocation = realsize * K;
  147.     }
  148. }
  149.  
  150.  
  151. //--------------------------------------------------------------------------
  152. //
  153. //      XMS::~XMS: release the XMS handle (if any).
  154. //
  155. XMS::~XMS ()
  156. {
  157.     if (handle)
  158.     {   _DX = handle;
  159.         _AH = 0x0A;
  160.         XMSdriver ();
  161.     }
  162. }
  163.  
  164. //--------------------------------------------------------------------------
  165. //
  166. //      XMS::resize.
  167. //
  168. //      Resize existing XMS allocation.
  169. //
  170. XMS::error XMS::resize (long newsize)
  171. {
  172.     error result = (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
  173.     int size;
  174.     if (handle)
  175.     {   result = SUCCESS;
  176.         newsize += K - 1;
  177.         int request = newsize / K;
  178.         _DX = handle;
  179.         _BX = request;
  180.         _AH = 0x0F;
  181.         XMSdriver ();
  182.         if (_AX != 0)
  183.         {   _DX = handle;
  184.             _AH = 0x0E;
  185.             XMSdriver ();
  186.             size = _DX;
  187.         }
  188.         if (_AX != 0)
  189.             allocation = size * K;
  190.         else
  191.             result = error (_BL);
  192.     }
  193.     return result;
  194. }
  195.  
  196.  
  197. //--------------------------------------------------------------------------
  198. //
  199. //      XMS::at.
  200. //
  201. //      Returns a descriptor identifying a particular byte offset in a
  202. //      particular XMS object for use in the "copy" operations below.
  203. //
  204. XMS::XMSptr XMS::at (long offset)
  205. {
  206.     XMSptr p = { handle, offset };
  207.     return p;
  208. }
  209.  
  210. //--------------------------------------------------------------------------
  211. //
  212. //      XMS::copy.
  213. //
  214. //      Copy from XMS to XMS.
  215. //
  216. XMS::error XMS::copy (const XMS::XMSptr& to,
  217.                       const XMS::XMSptr& from,
  218.                       unsigned len)
  219. {
  220.     if (from.handle == 0 || to.handle == 0)
  221.         return (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
  222.     descriptor.count     = len;
  223.     descriptor.srchandle = from.handle;
  224.     descriptor.srcoffset = from.offset;
  225.     descriptor.dsthandle = to.handle;
  226.     descriptor.dstoffset = to.offset;
  227.     return XMScopy ();
  228. }
  229.  
  230.  
  231. //--------------------------------------------------------------------------
  232. //
  233. //      XMS::copy.
  234. //
  235. //      Copy from XMS to conventional memory.
  236. //
  237. XMS::error XMS::copy (void far* to,
  238.                       const XMS::XMSptr& from,
  239.                       unsigned len)
  240. {
  241.     if (from.handle == 0)
  242.         return (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
  243.     descriptor.count     = len;
  244.     descriptor.srchandle = from.handle;
  245.     descriptor.srcoffset = from.offset;
  246.     descriptor.dsthandle = 0;
  247.     descriptor.dstoffset = long (to);
  248.     return XMScopy ();
  249. }
  250.  
  251.  
  252. //--------------------------------------------------------------------------
  253. //
  254. //      XMS::copy.
  255. //
  256. //      Copy from conventional memory to XMS.
  257. //
  258. XMS::error XMS::copy (const XMS::XMSptr& to,
  259.                       void far* from,
  260.                       unsigned len)
  261. {
  262.     if (to.handle == 0)
  263.         return (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
  264.     descriptor.count     = len;
  265.     descriptor.srchandle = 0;
  266.     descriptor.srcoffset = long (from);
  267.     descriptor.dsthandle = to.handle;
  268.     descriptor.dstoffset = to.offset;
  269.     return XMScopy ();
  270. }
  271.  
  272. //--------------------------------------------------------------------------
  273. //
  274. //      XMS::available.
  275. //
  276. //      Returns the total size of available XMS.
  277. //
  278. long XMS::available ()
  279. {
  280.     if (XMSinit () == SUCCESS)
  281.     {   _AH = 0x08;
  282.         XMSdriver ();
  283.         return _DX * K;
  284.     }
  285.     else
  286.         return 0;
  287. }
  288.  
  289.  
  290. //--------------------------------------------------------------------------
  291. //
  292. //      XMS::largest.
  293. //
  294. //      Returns the size of the largest unallocated XMS block available.
  295. //
  296. long XMS::largest ()
  297. {
  298.     if (XMSinit () == SUCCESS)
  299.     {   _AH = 0x08;
  300.         XMSdriver ();
  301.         return _AX * K;
  302.     }
  303.     else
  304.         return 0;
  305. }
  306.  
  307. //--------------------------------------------------------------------------
  308. //
  309. //      UMB::UMB.
  310. //
  311. //      Attempt to construct a UMB block of the specified size.
  312. //
  313. UMB::UMB (long size)
  314. {
  315.     address = 0;
  316.     allocation = 0;
  317.     if (size > (64 * K - 1) * PARA)
  318.         status = XMS::BLOCK_TOO_BIG;
  319.     else if ((status = XMSinit()) == XMS::SUCCESS)
  320.     {   size += PARA - 1;
  321.         _DX = unsigned (size/PARA);
  322.         _AH = 0x10;
  323.         XMSdriver ();
  324.         if (_AX != 0)
  325.         {   int bx = _BX;
  326.             address = MK_FP (bx,0);
  327.             allocation = unsigned (_DX);
  328.         }
  329.         else
  330.             status = XMS::error (_BL);
  331.     }
  332.     allocation *= PARA;
  333. }
  334.  
  335.  
  336. //--------------------------------------------------------------------------
  337. //
  338. //      UMB::~UMB.
  339. //
  340. //      Destroy UMB block if it has been created successfully.
  341. //
  342. UMB::~UMB ()
  343. {
  344.     if (address != 0)
  345.     {   _DX = FP_SEG (address);
  346.         _AH = 0x11;
  347.         XMSdriver ();
  348.     }
  349. }
  350.  
  351.  
  352. //--------------------------------------------------------------------------
  353. //
  354. //      UMB::largest.
  355. //
  356. //      Return size of largest available UMB block.
  357. //
  358. long UMB::largest ()
  359. {
  360.     long size = 0;
  361.     if (XMSinit () == XMS::SUCCESS)
  362.     {   _AH = 0x10;
  363.         _DX = 0xFFFF;
  364.         XMSdriver ();
  365.         size = unsigned (_DX);
  366.     }
  367.     return size * PARA;
  368. }
  369.  
  370. //--------------------------------------------------------------------------
  371. //
  372. //      HMA::HMA.
  373. //
  374. //      Attempt to allocate HMA for a block of the specified size.
  375. //
  376. HMA::HMA (unsigned size)
  377. {
  378.     allocation = 0;
  379.     if (size > (64 * K) - PARA)
  380.         status = XMS::BLOCK_TOO_BIG;
  381.     else if ((status = XMSinit()) == XMS::SUCCESS)
  382.     {   _DX = size;
  383.         _AH = 0x01;
  384.         XMSdriver ();
  385.         if (_AX != 0)
  386.         {   allocation = size;
  387.             _AH = 0x07;
  388.             XMSdriver ();
  389.             A20enabled = _AX;
  390.             if (!A20enabled)
  391.             {   _AH = 0x03;
  392.                 XMSdriver ();
  393.                 if (_AX != 0)
  394.                     return;
  395.             }
  396.         }
  397.         status = XMS::error (_BL);
  398.     }
  399. }
  400.  
  401.  
  402. //--------------------------------------------------------------------------
  403. //
  404. //      HMA::~HMA.
  405. //
  406. //      Release HMA if it has been allocated successfully.
  407. //
  408. HMA::~HMA ()
  409. {
  410.     if (status == XMS::SUCCESS)
  411.     {   _AH = 0x02;
  412.         XMSdriver ();
  413.         if (!A20enabled)
  414.         {   _AH = 0x04;
  415.             XMSdriver ();
  416.             A20enabled = !_AX;
  417.         }
  418.     }
  419. }
  420.  
  421.  
  422. //--------------------------------------------------------------------------
  423. //
  424. //      HMA::at.
  425. //
  426. HMA::HMAptr HMA::at (unsigned offset)
  427. {
  428.     HMAptr h = { this, offset };
  429.     return h;
  430. }
  431.  
  432. //--------------------------------------------------------------------------
  433. //
  434. //      HMA::copy.
  435. //
  436. //      Copy a block from one offset in the HMA to another.  The two
  437. //      blocks should not overlap.
  438. //
  439. unsigned HMA::copy (const HMAptr& to, const HMAptr& from, unsigned len)
  440. {
  441.     if (!to.hma->valid() || !from.hma->valid())
  442.         return 0;
  443.     if (len > to.hma->size() - to.offset)
  444.         len = to.hma->size() - to.offset;
  445.     if (len > from.hma->size() - from.offset)
  446.         len = from.hma->size() - from.offset;
  447.     _fmemcpy (MK_FP (0xFFFF, 0x0010 + to.offset),
  448.               MK_FP (0xFFFF, 0x0010 + from.offset),
  449.               len);
  450.     return len;
  451. }
  452.  
  453.  
  454. //--------------------------------------------------------------------------
  455. //
  456. //      HMA::copy.
  457. //
  458. //      Copy a block from the HMA to conventional memory.
  459. //
  460. unsigned HMA::copy (void far* to, const HMAptr& from, unsigned len)
  461. {
  462.     if (!from.hma->valid())
  463.         return 0;
  464.     if (len > from.hma->size() - from.offset)
  465.         len = from.hma->size() - from.offset;
  466.     _fmemcpy (to, MK_FP (0xFFFF, 0x0010 + from.offset), len);
  467.     return len;
  468. }
  469.  
  470.  
  471. //--------------------------------------------------------------------------
  472. //
  473. //      HMA::copy.
  474. //
  475. //      Copy a block from conventional memory to the HMA.
  476. //
  477. unsigned HMA::copy (const HMAptr& to, void far* from, unsigned len)
  478. {
  479.     if (!to.hma->valid())
  480.         return 0;
  481.     if (len > to.hma->size() - to.offset)
  482.         len = to.hma->size() - to.offset;
  483.     _fmemcpy (MK_FP (0xFFFF, 0x0010 + to.offset), from, len);
  484.     return len;
  485. }
  486.